/* m32c.opc --- semantics for m32c opcodes.		        -*- mode: c -*-

Copyright (C) 2005-2024 Free Software Foundation, Inc.
Contributed by Red Hat, Inc.

This file is part of the GNU simulators.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/* This must come before any other includes.  */
#include "defs.h"

#include <stdio.h>
#include <stdlib.h>

#include "ansidecl.h"
#include "cpu.h"
#include "mem.h"
#include "misc.h"
#include "int.h"

#define tprintf if (trace) printf

static unsigned char
getbyte (void)
{
  int tsave = trace;
  unsigned char b;

  if (trace == 1)
    trace = 0;
  b = mem_get_pc ();
  regs.r_pc ++;
  trace = tsave;
  return b;
}

#define M32C_ONLY() /* FIXME: add something here */

#define GETBYTE() (op[opi++] = getbyte())

#define UNSUPPORTED() unsupported("unsupported", m32c_opcode_pc)
#define NOTYET() unsupported("unimplemented", m32c_opcode_pc)

static void
unsupported (char *tag, int orig_pc)
{
  int i;
  printf("%s opcode at %08x\n", tag, orig_pc);
  regs.r_pc = orig_pc;
  for (i=0; i<2; i++)
    {
      int b = mem_get_pc();
      printf(" %s", bits(b>>4, 4));
      printf(" %s", bits(b, 4));
      regs.r_pc ++;
    }
  printf("\n");
  regs.r_pc = orig_pc;
  for (i=0; i<6; i++)
    {
      printf(" %02x", mem_get_pc ());
      regs.r_pc ++;
    }
  printf("\n");
  exit(1);
}

static int
IMM(int bytes)
{
  int rv = 0;
  switch (bytes)
    {
    case 1:
      rv = mem_get_qi (get_reg(pc));
      break;
    case 2:
      rv = mem_get_hi (get_reg(pc));
      break;
    case 3:
      rv = mem_get_psi (get_reg(pc));
      break;
    case 4:
      rv = mem_get_si (get_reg(pc));
      break;
    }
  regs.r_pc += bytes;
  return rv;
}

#define IMM4() (immm >= 8 ? 7 - immm : immm + 1)

#define NO_PREFIX() PREFIX(0,0,0)

/* Indicate which sorts of prefixes are allowed for the current
   opcode.  */
static void
prefix (int src_allowed, int dest_allowed, int index_bytewidth)
{
  /* At the moment, we don't do anything with this information.  We
     just wanted to get the information entered in some
     machine-readable form while we were going through all the
     opcodes.  */
}

#define MATH_OP(dc,s,c,op) \
{ \
  int ma, mb; \
  ma = get_src(dc); \
  mb = s & b2mask[dc.bytes]; \
  ll = (long long)ma op (long long)mb op c; \
  tprintf("0x%x " #op " 0x%x " #op " 0x%x = 0x%llx\n", ma, mb, c, ll); \
  ma = sign_ext (ma, dc.bytes * 8); \
  mb = sign_ext (s, dc.bytes * 8); \
  v = ma op mb op c; \
  tprintf("%d " #op " %d " #op " %d = %d\n", ma, mb, c, v); \
  set_oszc (v, dc.bytes, (1 op 1) ? (ll > b2mask[dc.bytes]) : (ll >= 0)); \
  put_dest (dc, v); \
}

#define LOGIC_OP(dc,s,op) \
{ \
  int ma, mb; \
  ma = get_src(dc); \
  mb = s & b2mask[dc.bytes]; \
  v = ma op mb; \
  tprintf("0x%x " #op " 0x%x = 0x%x\n", ma, mb, v); \
  set_sz (v, dc.bytes); \
  put_dest (dc, v); \
}

#define BIT_OP(dc,bit,expr)                                             \
  b = get_bit2 (dc, bitindex == -1 ? bit : bitindex);                   \
  v = expr;                                                             \
  tprintf ("b=%d, bit=%d, carry=%d, %s = %d\n",                         \
           b,  bitindex == -1 ? bit : bitindex, carry, #expr, v);       \
  put_bit2 (dc,  bitindex == -1 ? bit : bitindex, v);

#define BIT_OPC(dc,bit,expr)                                            \
  b = get_bit2 (dc,  bitindex == -1 ? bit : bitindex);                  \
  v = expr;                                                             \
  tprintf ("b=%d, bit=%d, carry=%d, %s = %d\n",                         \
           b,  bitindex == -1 ? bit : bitindex, carry, #expr, v);       \
  set_c (v);

#define carry (FLAG_C ? 1 : 0)

static void
cmp (int d, int s, int bytes)
{
  int a, b, f=0;
  a = d - s;
  b = sign_ext (d, bytes*8) - sign_ext (s, bytes*8);
  tprintf ("cmp: %x - %x = %08x, %x - %x = %d\n",
	   d, s, a,
	   sign_ext(d,bytes*8), sign_ext(s,bytes*8), b);

  if (b == 0)
    f |= FLAGBIT_Z;
  if (b & b2signbit[bytes])
    f |= FLAGBIT_S;
  if ((d & b2mask[bytes]) >= (s & b2mask[bytes]))
    f |= FLAGBIT_C;
  if (b < b2minsigned[bytes] || b > b2maxsigned[bytes])
    f |= FLAGBIT_O;

  set_flags (FLAGBIT_Z | FLAGBIT_S | FLAGBIT_O | FLAGBIT_C, f);
}

static void
dadd_op (int ddd, int dd, int sss, int ss, int imm, int add, int cy, int w)
{
  srcdest sc, dc;
  int a, b=0, res;

  prefix (0, 0, 0);

  if (!imm)
    {
      sc = decode_src23 (sss, ss, w+1);
      b = get_src (sc);
    }
  dc = decode_dest23 (ddd, dd, w+1);
  a = get_src (dc);
  if (imm)
    b = IMM(w+1);

  a = bcd2int(a, w);
  b = bcd2int(b, w);

  tprintf("decimal: %d %s %d", a, add?"+":"-", b);
  if (cy)
    tprintf(" c=%d", carry);

  if (add)
    {
      res = a + b;
      if (cy)
	res += carry;
      cy = res > (w ? 9999 : 99);
    }
  else
    {
      res = a - b;
      if (cy)
	res -= (1-carry);
      cy = res >= 0;
      if (res < 0)
	res += w ? 10000 : 100;
    }

  res = int2bcd (res, w);
  tprintf(" = %x\n", res);

  set_szc (res, w+1, cy);

  put_dest (dc, res);
}
#define DADDV(A,C) dadd_op(ddd, dd, sss, ss, 0, A, C, w)
#define DADDI(A,C) dadd_op(ddd, dd, 0, 0, 1, A, C, w)

static void
div_op (int sss, int ss, int u, int x, int bytes)
{
  srcdest sc;
  int s, v, a, b;

  if (sss == -1)
    s = IMM(bytes);
  else
    {
      sc = decode_dest23 (sss, ss, bytes);
      s = get_src (sc);
    }

  v = get_reg (bytes > 1 ? r2r0 : r0);

  if (!u)
    {
      /* FIXME? do we sign extend a0/a1 to .L?  Docs say zero extend.  */
      s = sign_ext (s, bytes*8);
      v = sign_ext (v, bytes*8);
    }

  if (s == 0)
    {
      set_flags (FLAGBIT_O, FLAGBIT_O);
      return;
    }

  if (u)
    {
      a = (unsigned int)v / (unsigned int)s;
      b = (unsigned int)v % (unsigned int)s;
    }
  else
    {
      a = v / s;
      b = v % s;
    }
  if (x)
    {
      if ((s > 0 && b < 0)
	  || (s < 0 && b > 0))
	{
	  a --;
	  b += s;
	}
    }
  tprintf ("%d / %d = %d rem %d\n", v, s, a, b);
  if ((!u && (a > b2maxsigned[bytes]
	      || a < b2minsigned[bytes]))
      || (u && (a > b2mask[bytes])))
    set_flags (FLAGBIT_O, FLAGBIT_O);
  else
    set_flags (FLAGBIT_O, 0);

  switch (bytes)
    {
    case 1:
      put_reg (r0l, a);
      put_reg (r0h, b);
      break;
    case 2:
      put_reg (r0, a);
      put_reg (r2, b);
      break;
    case 4:
      put_reg (r2r0, a);
      break;
    }
}

static void
index_op (int sss, int ss, int do_s, int do_d, int scale, int w)
{
  srcdest sc = decode_src23 (sss, ss, w+1);
  int v = get_src (sc) * scale;
  tprintf("%d = %d * %d, %d %d\n", v, get_src(sc), scale, do_s, do_d);
  decode_index (do_s * v, do_d * v);
}
#define INDEXOP(scale,do_s,do_d)                                \
  index_op (sss, ss, do_s, do_d, scale, w); goto next_opcode

static void
rot_op (srcdest sd, int rotc, int count)
{
  int mask = (sd.bytes == 2) ? 0xffff : 0xff;
  int msb = (sd.bytes == 2) ? 0x8000 : 0x80;
  int v = get_src (sd);
  int c = carry, ct;

  tprintf("%s %x by %d\n", rotc ? "rotc" : "rot", v, count);
  tprintf (": %s %d\n", bits(v, 8*sd.bytes), c);
  while (count > 0)
    {
      ct = (v & msb) ? 1 : 0;
      v <<= 1;
      v |= rotc ? c : ct;
      v &= mask;
      c = ct;
      tprintf (": %s %d\n", bits(v, 8*sd.bytes), c);
      count --;
    }
  while (count < 0)
    {
      ct = v & 1;
      v >>= 1;
      v |= (rotc ? c : ct) * msb;
      c = ct;
      tprintf (": %s %d\n", bits(v, 8*sd.bytes), c);
      count ++;
    }
  put_dest (sd, v);
  set_szc (v, sd.bytes, c);
}

static void
shift_op (srcdest sd, int arith, int count, int setc)
{
  int mask = (sd.bytes == 2) ? 0xffff : 0xff;
  int msb = (sd.bytes == 2) ? 0x8000 : 0x80;
  int v = get_src (sd);
  int c = 0;
  int o = 0;

  if (sd.bytes == 4)
    {
      mask = 0xffffffffU;
      msb = 0x80000000U;
    }

  tprintf("%s %x by %d\n", arith ? "sha" : "shl", v, count);
  tprintf (": %s %d %d\n", bits(v, 8*sd.bytes), c, o);
  while (count > 0)
    {
      c = (v & msb) ? 1 : 0;
      v <<= 1;
      v &= mask;
      if (c != ((v & msb) ? 1 : 0))
	o = 1;
      tprintf (": %s %d %d\n", bits(v, 8*sd.bytes), c, o);
      count --;
    }
  while (count < 0)
    {
      c = v & 1;
      if (arith)
	v = (v & msb) | (v >> 1);
      else
	v = (v >> 1) & (msb - 1);
      tprintf (": %s %d %d\n", bits(v, 8*sd.bytes), c, o);
      count ++;
    }
  put_dest (sd, v);
  set_sz (v, sd.bytes);
  if (setc)
    set_c (c);
  set_flags (FLAGBIT_O, o ? FLAGBIT_O : 0);
}

static int pcs[16];
static int ipcs = 0;

int
decode_m32c (void)
{
  unsigned char op[40];
  int opi;
  int v, a, b;
  long long ll;
  srcdest sc, dc;
  int imm;
  int bitindex = -1;
  int t0, t1=0, t2, t3=0;
  int ta0, ta1, dif;

  step_result = M32C_MAKE_STEPPED ();

  decode_indirect (0, 0);
  decode_index (0, 0);

next_opcode:
  opi = 0;
  m32c_opcode_pc = get_reg (pc);

  tprintf("trace: decode pc = %06x\n", m32c_opcode_pc);

  if (m32c_opcode_pc == 0)
    {
      int i;
      printf("Abort: PC is zero, here from:\n");
      for (i=0; i<4; i++)
	printf("  0x%06x\n", pcs[(ipcs+15-i)%16]);
      return M32C_MAKE_HIT_BREAK ();
    }
  pcs[ipcs++] = m32c_opcode_pc;
  ipcs %= 16;

  /** VARY sss 000 001 010 011 100 */
  /** VARY ddd 000 001 010 011 100 */

  /** 0000 1001				indirect dest */

  decode_indirect (0, 1);
  goto next_opcode;

  /** 0100 0001				indirect src */

  decode_indirect (1, 0);
  goto next_opcode;

  /** 0100 1001				indirect src and dest */

  decode_indirect (1, 1);
  goto next_opcode;

  /** 1010 ddd w dd01 1111		ABS.size dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  v = sign_ext (get_src (dc), w?16:8);
  a = v<0 ? -v : v;
  tprintf("abs(%d) = %d\n", v, a);
  set_osz(a, w+1);
  put_dest (dc, a);

  /** 0000 0001 1000 ddd w dd10 1110	ADC.size #IMM,dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  imm = IMM (w+1);
  MATH_OP (dc, imm, carry, +);

  /** 0000 0001 1sss ddd w dd ss 0100	ADC.size src,dest */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, w+1);
  dc = decode_dest23 (ddd, dd, w+1);
  b = get_src (sc);
  MATH_OP (dc, b, carry, +);

  /** 1011 ddd w dd01 1110		ADCF.size dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  MATH_OP (dc, 0, carry, +);

  /** 1000 ddd w dd10 1110		ADD.size:G #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23(ddd, dd, w+1);
  imm = IMM(w+1);
  MATH_OP (dc, imm, 0, +);

  /** 1000 ddd0 dd11 0001		ADD.L:G #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23(ddd, dd, 4);
  imm = IMM(4);
  MATH_OP (dc, imm, 0, +);

  /** 111L ddd w dd11 immm		ADD.size:Q #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23(ddd, dd, L ? 4 : (w+1));
  imm = sign_ext (immm, 4);
  MATH_OP (dc, imm, 0, +);

  /** 00dd 011w				ADD.size:S #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest2(dd, w+1);
  imm = IMM (w+1);
  MATH_OP (dc, imm, 0, +);

  /** 10i0 110d				ADD.L:S #IMM,A0/A1 */

  prefix (0, 0, 0);
  dc = reg_sd (d ? a1 : a0);
  imm = i ? 2 : 1;
  MATH_OP (dc, imm, 0, +);

  /** 1sss ddd w dd ss 1000		ADD.size:G src,dest */

  prefix (1, 1, 0);
  sc = decode_src23(sss, ss, w+1);
  dc = decode_dest23(ddd, dd, w+1);
  b = get_src (sc);
  MATH_OP (dc, b, 0, +);

  /** 1sss ddd1 dd ss 0010		ADD.L:G src,dest */

  prefix (1, 1, 0);
  sc = decode_src23(sss, ss, 4);
  dc = decode_dest23(ddd, dd, 4);
  b = get_src (sc);
  MATH_OP (dc, b, 0, +);

  /** 1011 0110 0001 0011		ADD.L:G #IMM16,SP */

  prefix (0, 0, 0);
  dc = reg_sd (sp);
  b = sign_ext (IMM(2), 16);
  MATH_OP (dc, b, 0, +);

  /** 01ii 001i				ADD.L:Q #IMM3,SP */

  prefix (0, 0, 0);
  dc = reg_sd (sp);
  b = ii * 2 + i + 1;
  MATH_OP (dc, b, 0, +);

  /** 1011 0110 0000 0011		ADD.L:S #IMM8,SP */

  prefix (0, 0, 0);
  dc = reg_sd (sp);
  b = sign_ext (IMM(1), 8);
  MATH_OP (dc, b, 0, +);

  /** 1000 ddd0 dd01 0001		ADDX #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23(ddd, dd, 4);
  imm = sign_ext (IMM(1), 8);
  MATH_OP (dc, imm, 0, +);

  /** 1sss ddd0 dd ss 0010		ADDX src,dest */

  prefix (1, 1, 0);
  sc = decode_src23(sss, ss, 1);
  dc = decode_dest23(ddd, dd, 4);
  b = sign_ext (get_src (sc), 8);
  MATH_OP (dc, b, 0, +);

  /** 1111 ddd w dd01 immm		ADJNZ.size #IMM,dest,label */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  v = get_src (dc);
  imm = sign_ext(immm, 4);
  tprintf("%d + %d = %d\n", v, imm, v+imm);
  v += imm;
  put_dest (dc, v);
  a = sign_ext (IMM(1), 8);
  if ((v & (w ? 0xffff : 0xff)) != 0)
    {
      tprintf("jmp: %x + 2 + %d = ", get_reg (pc), a);
      put_reg (pc, m32c_opcode_pc + 2 + a);
      tprintf("%x\n", get_reg (pc));
    }

  /** 1000 ddd w dd11 1111		AND.size:G #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23(ddd, dd, w+1);
  imm = IMM(w+1);
  LOGIC_OP (dc, imm, &);

  /** 01dd 110w				AND.size:S #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest2(dd, w+1);
  imm = IMM (w+1);
  LOGIC_OP (dc, imm, &);

  /** 1sss ddd w dd ss 1101		AND.size:G src,dest */

  prefix (1, 1, 0);
  sc = decode_src23(sss, ss, w+1);
  dc = decode_dest23(ddd, dd, w+1);
  b = get_src (sc);
  LOGIC_OP (dc, b, &);

  /** 0000 0001 1101 sss0 ss00 1bit	BAND src */

  sc = decode_src23 (sss, ss, 1);
  BIT_OPC (sc, bit, b & carry);

  /** 1101 ddd0 dd11 0bit		BCLR dest */

  dc = decode_dest23 (ddd, dd, 1);
  BIT_OP (dc, bit, 0);

  /** 1100 ddd w dd10 1110		BITINDEX.size src */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  bitindex = get_src (dc);
  tprintf ("bitindex set to %d\n", bitindex);
  goto next_opcode;

  /** 1101 ddd0 dd01 0bit		BMcnd dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, 1);
  if (condition_true (IMM (1)))
    put_bit2 (dc, bit, 1);
  else
    put_bit2 (dc, bit, 0);

  /** 1101 1001 0c10 1cnd		BMcnd C */

  prefix (0, 0, 0);
  if (condition_true (c * 8 + cnd))
    set_c (1);
  else
    set_c (0);

  /** 0000 0001 1101 sss0 ss01 1bit	BNAND src */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 1);
  BIT_OPC (sc, bit, (!b) & carry);

  /** 0000 0001 1101 sss0 ss11 0bit	BNOR src */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 1);
  BIT_OPC (sc, bit, (!b) | carry);

  /** 1101 ddd0 dd01 1bit		BNOT dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, 1);
  BIT_OP (dc, bit, !b);

  /** 0000 0001 1101 sss0 ss00 0bit	BNTST src */

  prefix (0, 0, 0);
  sc = decode_dest23 (sss, ss, 1);
  b = get_bit2 (sc, bit);
  set_zc (!b, !b);

  /** 0000 0001 1101 sss0 ss11 1bit	BNXOR src */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 1);
  BIT_OPC (sc, bit, !b ^ carry);

  /** 0000 0001 1101 sss0 ss10 0bit	BOR src */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 1);
  BIT_OPC (sc, bit, b | carry);

  /** 0000 0000				BRK */

  /* We report the break to our caller with the PC still pointing at the 
     breakpoint instruction.  */
  put_reg (pc, m32c_opcode_pc);
  if (verbose)
    printf("[break]\n");
  if (in_gdb || (regs.r_intbl == 0 && regs.r_intbh == 0))
    return M32C_MAKE_HIT_BREAK ();
  if (mem_get_qi (0xFFFFE7) == 0xff)
    trigger_based_interrupt (0);
  else
    trigger_fixed_interrupt (0xFFFFE4);

  /** 1111 1110				GBRK */

  /* This alternate break, which is not part of the chip's opcode set,
   is here in case you need to debug a program that itself uses the
   chip's BRK opcode.  You'll need to modify your copy of GDB to use
   this opcode instead of the real BRK.  */

  /* GDB Break. */
  /* We report the break to our caller with the PC still pointing at the 
     breakpoint instruction.  */
  put_reg (pc, m32c_opcode_pc);
  if (verbose)
    printf("[gdb break]\n");
  return M32C_MAKE_HIT_BREAK ();

  /** 0000 1000				BRK2 */

  if (verbose)
    printf("[break2]\n");
  if (in_gdb)
    return M32C_MAKE_HIT_BREAK ();
  if (mem_get_qi (0xFFFFE7) == 0xff)
    trigger_based_interrupt (0);
  else
    trigger_fixed_interrupt (0xFFFFE4);

  /** 1101 ddd0 dd11 1bit		BSET dest */

  dc = decode_dest23 (ddd, dd, 1);
  BIT_OP (dc, bit, 1);

  /** 1101 sss0 ss00 0bit		BTST:G src */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 1);
  b = get_bit2 (sc, bit);
  set_zc (!b, b);

  /** 00bb 101bit			BTST:S src */

  sc = decode_src23 (3, 3, 1); /* bit,base:19 */
  bit = get_bit2 (sc, bb*2 + bit);
  set_zc (!bit, bit);

  /** 1101 ddd0 dd10 0bit		BTSTC dest */

  prefix (0, 0, 0);
  sc = decode_dest23 (ddd, dd, 1);
  b = get_bit2 (sc, bit);
  set_zc (!b, b);
  put_bit2 (sc, bit, 0);

  /** 1101 ddd0 dd10 1bit		BTSTS dest */

  prefix (0, 0, 0);
  sc = decode_dest23 (ddd, dd, 1);
  b = get_bit2 (sc, bit);
  set_zc (!b, b);
  put_bit2 (sc, bit, 1);

  /** 0000 0001 1101 sss0 ss10 1bit	BXOR src */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 1);
  BIT_OPC (sc, bit, b ^ carry);

  /** 0000 0001 1000 ddd w dd11 1110	CLIP.size #IMM1,#IMM2,dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  a = sign_ext (IMM(w+1), w*8+8);
  b = sign_ext (IMM(w+1), w*8+8);
  v = sign_ext (get_src (dc), w*8+8);
  tprintf("clip %d <= %d <= %d : ", a, v, b);
  if (a > v)
    v = a;
  if (v > b)
    v = b;
  tprintf("%d\n", v);
  put_dest (dc, v);

  /** 1001 ddd w dd10 1110		CMP.size:G #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  v = get_src (dc);
  imm = IMM(w+1);
  cmp (v, imm, w+1);

  /** 1010 ddd0 dd11 0001		CMP.L:G #IMM32,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, 4);
  v = get_src (dc);
  imm = IMM(4);
  cmp (v, imm, 4);

  /** 1110 ddd w dd01 immm		CMP.size:Q #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  v = get_src (dc);
  immm = sign_ext (immm, 4);
  cmp (v, immm, w+1);

  /** 01dd 011w				CMP.size:S #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest2 (dd, w+1);
  v = get_src (dc);
  imm = sign_ext (IMM(w+1),w*8+8);
  cmp (v, imm, w+1);

  /** 1sss ddd w dd ss 0110		CMP.size:G src,dest */

  prefix (1, 1, 0);
  sc = decode_src23 (sss, ss, w+1);
  dc = decode_dest23 (ddd, dd, w+1);
  a = get_src (dc);
  b = get_src (sc);
  cmp (a, b, w+1);

  /** 1sss ddd1 dd ss 0001		CMP.L:G src,dest */

  prefix (1, 1, 0);
  sc = decode_src23 (sss, ss, 4);
  dc = decode_dest23 (ddd, dd, 4);
  a = get_src (dc);
  b = get_src (sc);
  cmp (a, b, 4);

  /** 01dd 000w				CMP.size:S src,R0/R0L */

  prefix (0, 1, 0);
  dc = decode_dest2 (dd, w+1);
  a = get_reg (w ? r0 : r0l);
  b = get_src (dc);
  cmp (a, b, w+1);

  /** 1010 ddd0 dd01 0001		CMPX #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, 4);
  v = get_src (dc);
  imm = sign_ext (IMM(1), 8);
  cmp (v, imm, 4);

  /** 0000 0001 1000 ddd w dd00 1110	DADC.size #IMM,dest */

  DADDI(1,1);

  /** 0000 0001 1sss ddd w dd ss 1000	DADC.size src,dest */

  DADDV(1,1);

  /** 0000 0001 1000 ddd w dd01 1110	DADD.size #IMM,dest */

  DADDI(1,0);

  /** 0000 0001 1sss ddd w dd ss 0000	DADD.size src,dest */

  DADDV(1,0);

  /** 1011 ddd w dd00 1110		DEC.size dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  a = get_src (dc);
  v = a-1;
  tprintf ("%x -- = %x\n", a, v);
  set_sz (v, w+1);
  put_dest (dc, v);

  /** 1011 0000 010w 0011		DIV.size #IMM */

  prefix (0, 0, 0);
  div_op (-1, 0, 0, 0, w+1);

  /** 1000 sss w ss01 1110		DIV.size src */

  prefix (0, 1, 0);
  div_op (sss, ss, 0, 0, w+1);

  /** 0000 0001 1010 sss1 ss01 1111	DIV.L src */

  M32C_ONLY();
  prefix (0, 0, 0);
  div_op (sss, ss, 0, 0, 4);

  /** 1011 0000 000w 0011		DIVU.size #IMM */

  prefix (0, 0, 0);
  div_op (-1, 0, 1, 0, w+1);

  /** 1000 sss w ss00 1110		DIVU.size src */

  prefix (0, 1, 0);
  div_op (sss, ss, 1, 0, w+1);

  /** 0000 0001 1010 sss1 ss00 1111	DIVU.L src */

  M32C_ONLY();
  prefix (0, 0, 0);
  div_op (sss, ss, 1, 0, 4);

  /** 1011 0010 010w 0011		DIVX.size #IMM */

  prefix (0, 0, 0);
  div_op (-1, 0, 0, 1, w+1);

  /** 1001 sss w ss01 1110		DIVX.size src */

  prefix (0, 1, 0);
  div_op (sss, ss, 0, 1, w+1);

  /** 0000 0001 1010 sss1 ss10 1111	DIVX.L src */

  M32C_ONLY();
  prefix (0, 0, 0);
  div_op (sss, ss, 0, 1, 4);

  /** 0000 0001 1001 ddd w dd00 1110	DSBB.size #IMM,dest */

  DADDI(0,1);

  /** 0000 0001 1sss ddd w dd ss 1010	DSBB.size src,dest */

  DADDV(0,1);

  /** 0000 0001 1001 ddd w dd01 1110	DSUB.size #IMM,dest */

  DADDI(0,0);

  /** 0000 0001 1sss ddd w dd ss 0010	DSUB.size src,dest */

  DADDV(0,0);

  /** 1110 1100				ENTER #IMM */

  imm = IMM(1);
  put_reg (sp, get_reg (sp) - 4);
  mem_put_si (get_reg (sp), get_reg (fb));
  put_reg (fb, get_reg (sp));
  put_reg (sp, get_reg (sp) - imm);

  /** 1111 1100				EXITD */

  put_reg (sp, get_reg (fb));
  put_reg (fb, mem_get_si (get_reg (sp)));
  put_reg (sp, get_reg (sp) + 4);
  put_reg (pc, mem_get_si (get_reg (sp)));
  put_reg (sp, get_reg (sp) + 4);

  /** 1100 ddd w dd01 1110		EXTS.size dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  v = sign_ext (get_src (dc), (w+1)*8);
  dc = widen_sd (dc);
  put_dest (dc, v);
  set_sz (v, (w+1)*2);

  /** 0000 0001 1sss ddd0 dd ss 0111	EXTS.B src,dest */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 1);
  dc = decode_dest23 (ddd, dd, 2);
  v = sign_ext (get_src (sc), 8);
  put_dest (dc, v);
  set_sz (v, 16);

  /** 0000 0001 1sss ddd0 dd ss 1011	EXTZ src,dest */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 1);
  dc = decode_dest23 (ddd, dd, 2);
  v = get_src (sc);
  put_dest (dc, v);
  set_sz (v, 16);

  /** 1101 0011 1110 1dst		FCLR dest */

  set_flags (1 << dst, 0);

  /** 1001 1111				FREIT */

  NOTYET();

  /** 1101 0001 1110 1dst		FSET dest */
  
  set_flags (1 << dst, 1 << dst);

  /** 1010 ddd w dd00 1110		INC.size dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  a = get_src (dc);
  v = a+1;
  tprintf ("%x ++ = %x\n", a, v);
  set_sz (v, w+1);
  put_dest (dc, v);

  /** 1000 sss0 ss0w 0011		INDEXB.size src */
  INDEXOP(1, 1, 1);
  /** 1010 sss0 ss0w 0011		INDEXBD.size src */
  INDEXOP(1, 0, 1);
  /** 1100 sss0 ss0w 0011		INDEXBS.size src */
  INDEXOP(1, 1, 0);
  /** 1001 sss0 ss1w 0011		INDEXL.size src */
  INDEXOP(4, 1, 1);
  /** 1011 sss0 ss1w 0011		INDEXLD.size src */
  INDEXOP(4, 0, 1);
  /** 1001 sss0 ss0w 0011		INDEXLS.size src */
  INDEXOP(4, 1, 0);
  /** 1000 sss0 ss1w 0011		INDEXW.size src */
  INDEXOP(2, 1, 1);
  /** 1010 sss0 ss1w 0011		INDEXWD.size src */
  INDEXOP(2, 0, 1);
  /** 1100 sss0 ss1w 0011		INDEXWS.size src */
  INDEXOP(2, 1, 0);

  /** 1011 1110 vector00			INT #IMM */

  prefix (0, 0, 0);
  trigger_based_interrupt (vector);

  /** 1011 1111				INTO */

  prefix (0, 0, 0);
  if (FLAG_O)
    trigger_fixed_interrupt (0xffffe0);

  /** 1ccc 101c				Jcnd label */

  prefix (0, 0, 0);
  v = sign_ext (IMM(1), 8);
  if (condition_true (ccc*2+c))
    put_reg (pc, m32c_opcode_pc + 1 + v);

  /** 01dd 101d				JMP.S label */

  prefix (0, 0, 0);
  put_reg (pc, m32c_opcode_pc + (dd*2+d) + 2);

  /** 1011 1011				JMP.B label */

  prefix (0, 0, 0);
  imm = sign_ext (IMM(1), 8);
  if (imm == -1)
    {
      if (verbose)
	printf("[jmp-to-self detected as exit]\n");
      return M32C_MAKE_HIT_BREAK ();
    }
  put_reg (pc, m32c_opcode_pc + 1 + imm);

  /** 1100 1110				JMP.W label */

  prefix (0, 0, 0);
  imm = sign_ext (IMM(2), 16);
  put_reg (pc, m32c_opcode_pc + 1 + imm);

  /** 1100 1100				JMP.A label */
  
  prefix (0, 0, 0);
  imm = IMM(3);
  put_reg (pc, imm);

  /** 1100 sss1 ss00 1111		JMPI.W src */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 2);
  a = get_src (sc);
  a = sign_ext (a, 16);
  put_reg (pc, m32c_opcode_pc + a);

  /** 1000 sss0 ss00 0001		JMPI.A src */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 3);
  a = get_src (sc);
  put_reg (pc, a);

  /** 1101 1100				JMPS #IMM8 */

  prefix (0, 0, 0);
  imm = IMM(1);
  a = 0xff0000 + mem_get_hi (0xfffe00 - imm * 2);
  put_reg (pc, a);

  /** 1100 1111				JSR.W label */

  prefix (0, 0, 0);
  imm = sign_ext (IMM(2), 16);
  put_reg (sp, get_reg (sp) - 4);
  mem_put_si (get_reg (sp), get_reg (pc));
  put_reg (pc, m32c_opcode_pc + imm + 1);

  /** 1100 1101				JSR.A label */

  prefix (0, 0, 0);
  imm = IMM(3);
  put_reg (sp, get_reg (sp) - 4);
  mem_put_si (get_reg (sp), get_reg (pc));
  put_reg (pc, imm);

  /** 1100 sss1 ss01 1111		JSRI.W src */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 2);
  a = get_src (sc);
  a = sign_ext (a, 16);
  put_reg (sp, get_reg (sp) - 4);
  mem_put_si (get_reg (sp), get_reg (pc));
  put_reg (pc, m32c_opcode_pc + a);

  /** 1001 sss0 ss00 0001		JSRI.A src */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 3);
  a = get_src (sc);
  put_reg (sp, get_reg (sp) - 4);
  mem_put_si (get_reg (sp), get_reg (pc));
  put_reg (pc, a);

  /** 1101 1101				JSRS #IMM8 */

  prefix (0, 0, 0);
  imm = IMM(1);
  a = 0xff0000 + mem_get_hi (0xfffe00 - imm * 2);
  put_reg (sp, get_reg (sp) - 4);
  mem_put_si (get_reg (sp), get_reg (pc));
  put_reg (pc, a);

  /** 1101 0101 1010 1dst		LDC #IMM16,dest */

  imm = IMM(2);
  dc = decode_cr_b (dst, CR_B_DCT0);
  put_dest (dc, imm);

  /** 1101 0101 0010 1dst		LDC #IMM24,dest */

  imm = IMM(3);
  dc = decode_cr_b (dst, CR_B_INTB);
  put_dest (dc, imm);

  /** 1101 0101 0110 1dst		LDC #IMM24,dest */

  imm = IMM(3);
  dc = decode_cr_b (dst, CR_B_DMA0);
  put_dest (dc, imm);

  /** 0000 0001 1101 sss1 ss00 1dst	LDC src,dest */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 2);
  dc = decode_cr_b (dst, CR_B_DCT0);
  a = get_src (sc);
  put_dest (dc, a);

  /** 1101 sss1 ss00 0dst		LDC src,dest */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 3);
  dc = decode_cr_b (dst, CR_B_INTB);
  a = get_src (sc);
  put_dest (dc, a);

  /** 0000 0001 1101 sss1 ss00 0dst	LDC src,dest */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 3);
  dc = decode_cr_b (dst, CR_B_DMA0);
  a = get_src (sc);
  put_dest (dc, a);

  /** 1011 0110 1100 0011		LDCTX */

  NOTYET();

  /** 1101 0101 1110 1flg		LDIPL #IMM */

  set_flags (0x7000, flg*0x1000);

  /** 0000 0001 1000 ddd w dd11 1111	MAX.size #IMM,dest */

  prefix (0, 0, 0);
  w++;
  dc = decode_dest23 (ddd, dd, w);
  imm = sign_ext (IMM(w), w*8);
  a = sign_ext (get_src (dc), w*8);
  tprintf ("max %d %d\n", imm, a);
  if (imm > a)
    put_dest (dc, imm);

  /** 0000 0001 1sss ddd w dd ss 1101	MAX.size src,dest */

  prefix (0, 0, 0);
  w++;
  sc = decode_src23 (sss, ss, w);
  dc = decode_dest23 (ddd, dd, w);
  b = sign_ext (get_src (sc), w*8);
  a = sign_ext (get_src (dc), w*8);
  tprintf ("max %d %d\n", b, a);
  if (b > a)
    put_dest (dc, b);

  /** 0000 0001 1000 ddd w dd10 1111	MIN.size #IMM,dest */

  prefix (0, 0, 0);
  w++;
  dc = decode_dest23 (ddd, dd, w);
  imm = sign_ext (IMM(w), w*8);
  a = sign_ext (get_src (dc), w*8);
  tprintf ("min %d %d\n", imm, a);
  if (imm < a)
    put_dest (dc, imm);

  /** 0000 0001 1sss ddd w dd ss 1100	MIN.size src,dest */

  prefix (0, 0, 0);
  w++;
  sc = decode_src23 (sss, ss, w);
  dc = decode_dest23 (ddd, dd, w);
  b = sign_ext (get_src (sc), w*8);
  a = sign_ext (get_src (dc), w*8);
  tprintf ("min %d %d\n", b, a);
  if (b < a)
    put_dest (dc, b);

  /** 1001 ddd w dd10 1111		MOV.size:G #IMM,dest */

  dc = decode_dest23 (ddd, dd, w+1);
  imm = IMM(w+1);
  v = imm;
  tprintf("%x = %x\n", v, v);
  set_sz(v, w+1);
  put_dest (dc, v);

  /** 1011 ddd0 dd11 0001		MOV.L:G #IMM,dest */

  dc = decode_dest23 (ddd, dd, 4);
  imm = IMM(4);
  v = imm;
  tprintf("%x = %x\n", v, v);
  set_sz(v, 4);
  put_dest (dc, v);

  /** 1111 ddd w dd10 immm		MOV.size:Q #IMM4,dest */

  dc = decode_dest23 (ddd, dd, w+1);
  imm = sign_ext (immm, 4);
  v = imm;
  tprintf("%x = %d\n", v, v);
  set_sz(v, w+1);
  put_dest (dc, v);

  /** 00dd 010w				MOV.size:S #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest2 (dd, w+1);
  imm = IMM(w+1);
  put_dest (dc, imm);
  set_sz (imm, w+1);

  /** 10w1 110d				MOV.size:S #IMM,a0/a1 */

  imm = IMM(w ? 3 : 2);
  put_reg (d ? a1 : a0, imm);
  set_sz (imm & addr_mask, w+1);

  /** 00dd 001w				MOV.size:Z #0,dest */

  prefix (0, 1, 0);
  dc = decode_dest2 (dd, w+1);
  put_dest (dc, 0);
  set_sz (0, w+1);

  /** 1sss ddd w dd ss 1011		MOV.size:G src,dest */

  prefix (1, 1, 0);
  sc = decode_src23 (sss, ss, w+1);
  dc = decode_dest23 (ddd, dd, w+1);
  v = get_src (sc);
  put_dest (dc, v);
  set_sz (v, w+1);

  /** 1sss ddd1 dd ss 0011		MOV.L:G src,dest */

  prefix (1, 1, 0);
  sc = decode_src23 (sss, ss, 4);
  dc = decode_dest23 (ddd, dd, 4);
  v = get_src (sc);
  put_dest (dc, v);
  set_sz (v, 4);

  /** VARY SS 01 10 11 */
  /** 00SS 100w				MOV.size:S src,R0L/R0 */

  prefix (0, 1, 0);
  sc = decode_dest2 (SS, w+1);
  v = get_src (sc);
  put_reg (w ? r0 : r0l, v);
  set_sz (v, w+1);

  /** 01ss 111w				MOV.size:S src,R1L/R1 */

  prefix (0, 1, 0);
  sc = decode_dest2 (ss, w+1);
  v = get_src (sc);
  put_reg (w ? r1 : r1l, v);
  set_sz (v, w+1);

  /** VARY DD 01 10 11 */
  /** 00DD 000w				MOV.size:S R0L/R0,dest */

  prefix (0, 1, 0);
  dc = decode_dest2 (DD, w+1);
  v = get_reg (w ? r0 : r0l);
  put_dest (dc, v);
  set_sz (v, w+1);

  /** 01ss 100d				MOV.L:S src,A0/A1 */

  prefix (0, 1, 0);
  sc = decode_dest2 (ss, 4);
  v = get_src (sc);
  put_reg (d ? a1 : a0, v);
  set_sz (v, 4);

  /** 1011 ddd w dd00 1111		MOV.size:G dsp:8[SP], dest */

  prefix (0, 0, 0);
  imm = IMM(1);
  dc = decode_dest23 (ddd, dd, w+1);
  a = get_reg (sp) + sign_ext (imm, 8);
  a &= addr_mask;
  if (w)
    v = mem_get_hi (a);
  else
    v = mem_get_qi (a);
  put_dest (dc, v);
  set_sz (v, w+1);

  /** 1010 sss w ss00 1111		MOV.size:G src,dsp:8[SP] */

  prefix (0, 0, 0);
  sc = decode_dest23 (sss, ss, w+1);
  imm = IMM(1);
  a = get_reg (sp) + sign_ext (imm, 8);
  a &= addr_mask;
  v = get_src (sc);
  if (w)
    mem_put_hi (a, v);
  else
    mem_put_qi (a, v);
  set_sz (v, w+1);

  /** 1101 sss1 ss01 1dst		MOVA src,dest */

  {
  static reg_id map[8] = { r2r0, r3r1, a0, a1 };
  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 1);
  if (!sc.mem || !map[dst])
    UNSUPPORTED();
  put_reg (map[dst], sc.u.addr);
  }

  /** 0000 0001 1011 ddd0 dd hl 1110	MOVdir R0L,dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, 1);
  a = get_src (dc);
  b = get_reg (r0l);
  switch (hl)
    {
    case 0: a = (a & 0xf0) | (b & 0x0f); break;
    case 1: a = (a & 0xf0) | ((b>>4) & 0x0f); break;
    case 2: a = (a & 0x0f) | ((b & 0x0f)<<4); break;
    case 3: a = (a & 0x0f) | (b & 0xf0); break;
    }
  put_dest (dc, a);

  /** 0000 0001 1010 sss0 ss hl 1110	MOVdir src,R0L */

  prefix (0, 0, 0);
  sc = decode_dest23 (sss, ss, 1);
  a = get_reg (r0l);
  b = get_src (dc);
  switch (hl)
    {
    case 0: a = (a & 0xf0) | (b & 0x0f); break;
    case 1: a = (a & 0xf0) | ((b>>4) & 0x0f); break;
    case 2: a = (a & 0x0f) | ((b & 0x0f)<<4); break;
    case 3: a = (a & 0x0f) | (b & 0xf0); break;
    }
  put_reg (r0l, a);

  /** 1011 ddd0 dd01 0001		MOVX #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, 4);
  imm = sign_ext (IMM(1), 8);
  put_dest (dc, imm);
  set_sz (imm, 1);

  /** 1000 ddd w dd01 1111		MUL.size #IMM,dest */

  prefix (0, 1, 0);
  w ++;
  dc = decode_dest23 (ddd, dd, w);
  v = sign_ext (get_src (dc), w*8);
  imm = sign_ext (IMM(w), w*8);
  tprintf("%d * %d = %d\n", v, imm, v*imm);
  v *= imm;
  dc = widen_sd (dc);
  put_dest (dc, v);

  /** 1sss ddd w dd ss 1100		MUL.size src,dest */

  prefix (1, 1, 0);
  w ++;
  sc = decode_src23 (sss, ss, w);
  dc = decode_dest23 (ddd, dd, w);
  a = sign_ext (get_src (sc), w*8);
  b = sign_ext (get_src (dc), w*8);
  tprintf("%d * %d = %d\n", a, b, a*b);
  v = a * b;
  dc = widen_sd (dc);
  put_dest (dc, v);

  /** 0000 0001 1000 sss1 ss01 1111	MUL.L src,R2R0 */

  M32C_ONLY();
  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 4);
  a = sign_ext (get_src (sc), 32);
  b = sign_ext (get_reg (r2r0), 32);
  ll = (long long)a * (long long)b;
  tprintf("%d * %d = %lld (%llx)\n", a, b, ll, ll);
  if (ll < b2minsigned[4] || ll > b2maxsigned[4])
    set_flags (FLAGBIT_O, FLAGBIT_O);
  else
    set_flags (FLAGBIT_O, 0);
  put_reg (r2r0, (int)ll);

  /** 1100 sss1 ss11 1110		MULEX src */

  prefix (0, 1, 0);
  sc = decode_dest23 (sss, ss, 2);
  a = sign_ext (get_src (sc), 16);
  b = sign_ext (get_reg (r2r0), 32);
  ll = (long long)a * (long long)b;
  tprintf("%d * %d = %lld (%llx)\n", a, b, ll, ll);
  put_reg (r2r0, (int)ll);
  put_reg (r1, (int)(ll >> 32));

  /** 1000 ddd w dd00 1111		MULU.size #IMM,dest */

  prefix (0, 1, 0);
  w ++;
  dc = decode_dest23 (ddd, dd, w);
  v = get_src (dc);
  imm = IMM(w);
  tprintf("%d * %d = %d\n", v, imm, v*imm);
  v *= imm;
  dc = widen_sd (dc);
  put_dest (dc, v);

  /** 1sss ddd w dd ss 0100		MULU.size src,dest */

  prefix (1, 1, 0);
  w ++;
  sc = decode_src23 (sss, ss, w);
  dc = decode_dest23 (ddd, dd, w);
  a = get_src (sc);
  b = get_src (dc);
  tprintf("%d * %d = %d\n", a, b, a*b);
  v = a * b;
  dc = widen_sd (dc);
  put_dest (dc, v);

  /** 0000 0001 1000 sss1 ss00 1111	MULU.L src,R2R0 */

  M32C_ONLY();
  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, 4);
  a = get_src (sc);
  b = get_reg (r2r0);
  ll = (long long)a * (long long)b;
  tprintf("%d * %d = %lld (%llx)\n", a, b, ll, ll);
  if (ll < b2minsigned[4] || ll > b2maxsigned[4])
    set_flags (FLAGBIT_O, FLAGBIT_O);
  else
    set_flags (FLAGBIT_O, 0);
  put_reg (r2r0, (int)ll);

  /** 1010 ddd w dd10 1111		NEG.size dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  a = sign_ext (get_src (dc), (w+1)*8);
  v = -a;
  tprintf("%d * -1 = %d\n", a, v);
  set_oszc(v, w+1, v==0);
  put_dest (dc, v);

  /** 1101 1110				NOP */

  tprintf("nop\n");

  /** 1010 ddd w dd01 1110		NOT.size dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  a = get_src (dc);
  v = ~a;
  tprintf("~ %x = %x\n", a, v);
  set_sz(v, w+1);
  put_dest (dc, v);

  /** 1000 ddd w dd10 1111		OR.size:G #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23(ddd, dd, w+1);
  imm = IMM(w+1);
  LOGIC_OP (dc, imm, |);

  /** 01dd 010w				OR.size:S #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest2(dd, w+1);
  imm = IMM (w+1);
  LOGIC_OP (dc, imm, |);

  /** 1sss ddd w dd ss 0101		OR.size:G src,dest */

  prefix (1, 1, 0);
  sc = decode_src23(sss, ss, w+1);
  dc = decode_dest23(ddd, dd, w+1);
  b = get_src (sc);
  LOGIC_OP (dc, b, |);

  /** 1011 ddd w dd10 1111		POP.size dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  if (w)
    a = mem_get_hi (get_reg (sp));
  else
    a = mem_get_qi (get_reg (sp));
  put_reg (sp, get_reg (sp) + 2);
  tprintf("pop%s: %x\n", w ? "hi" : "qi", a);
  put_dest (dc, a);

  /** 1101 0011 1010 1dst		POPC dest */

  prefix (0, 0, 0);
  dc = decode_cr_b (dst, CR_B_DCT0);
  a = mem_get_hi (get_reg (sp));
  put_reg (sp, get_reg (sp) + 2);
  tprintf("pophi: %x\n", a);
  put_dest (dc, a);

  /** 1101 0011 0010 1dst		POPC dest */

  prefix (0, 0, 0);
  dc = decode_cr_b (dst, CR_B_INTB);
  a = mem_get_si (get_reg (sp));
  put_reg (sp, get_reg (sp) + 4);
  tprintf("popsi: %x\n", a);
  put_dest (dc, a);

  /** 1000 1110				POPM dest */

  {
  static int map[] = { r0, r1, r2, r3, a0, a1, sb, fb };
  prefix (0, 0, 0);
  imm = IMM(1);
  tprintf("popm: %x\n", imm);
  for (a=0; a<4; a++)
    if (imm & (1<<a))
      {
	v = mem_get_hi (get_reg (sp));
	put_reg (map[a], v);
	put_reg (sp, get_reg (sp) + 2);
      }
  for (; a<8; a++)
    if (imm & (1<<a))
      {
	v = mem_get_si (get_reg (sp));
	put_reg (map[a], v);
	put_reg (sp, get_reg (sp) + 4);
      }
  }

  /** 1010 111w				PUSH.size #IMM */

  prefix (0, 0, 0);
  imm = IMM(w+1);
  tprintf("push%s: %x\n", w ? "hi" : "qi", imm);
  a = get_reg (sp) - 2;
  if (w)
    mem_put_hi (a, imm);
  else
    mem_put_qi (a, imm);
  put_reg (sp, a);

  /** 1100 sss w ss00 1110		PUSH.size src */

  prefix (0, 1, 0);
  sc = decode_dest23 (sss, ss, w+1);
  a = get_src (sc);
  put_reg (sp, get_reg (sp) - 2);
  if (w)
    mem_put_hi (get_reg (sp), a);
  else
    mem_put_qi (get_reg (sp), a);
  tprintf("push%s: %x\n", w ? "hi" : "qi", a);

  /** 1011 0110 0101 0011		PUSH.L #IMM32 */

  imm = IMM(4);
  put_reg (sp, get_reg (sp) - 4);
  mem_put_si (get_reg (sp), imm);

  /** 1010 sss0 ss00 0001		PUSH.L src */

  prefix (0, 1, 0);
  sc = decode_dest23 (sss, ss, 4);
  a = get_src (sc);
  put_reg (sp, get_reg (sp) - 4);
  mem_put_si (get_reg (sp), a);

  /** 1011 0sa0 ss00 0001		PUSHA src */

  prefix (0, 0, 0);
  sc = decode_dest23 (sa, ss, 1);
  put_reg (sp, get_reg (sp) - 4);
  mem_put_hi (get_reg (sp), sc.u.addr);
  tprintf("pushsi: %x\n", sc.u.addr);

  /** 1101 0001 1010 1src		PUSHC src */

  prefix (0, 0, 0);
  sc = decode_cr_b (src, CR_B_DCT0);
  a = get_src (sc);
  put_reg (sp, get_reg (sp) - 2);
  mem_put_hi (get_reg (sp), a);
  tprintf("pushhi: %x\n", a);

  /** 1101 0001 0010 1src		PUSHC src */

  prefix (0, 0, 0);
  sc = decode_cr_b (src, CR_B_INTB);
  a = get_src (sc);
  put_reg (sp, get_reg (sp) - 4);
  mem_put_si (get_reg (sp), a);
  tprintf("pushsi: %x\n", a);

  /** 1000 1111				PUSHM src */

  {
  static int map[] = { fb, sb, a1, a0, r3, r2, r1, r0 };
  imm = IMM(1);
  tprintf("pushm: %x\n", imm);
  for (a=0; a<4; a++)
    if (imm & (1<<a))
      {
	put_reg (sp, get_reg (sp) - 4);
	v = get_reg (map[a]);
	mem_put_si (get_reg (sp), v);
      }
  for (; a<8; a++)
    if (imm & (1<<a))
      {
	put_reg (sp, get_reg (sp) - 2);
	v = get_reg (map[a]);
	mem_put_hi (get_reg (sp), v);
      }
  }

  /** 1001 1110				REIT */

  a = get_reg (sp);
  put_reg (pc, mem_get_si (a));
  a += 4;
  put_reg (flags, mem_get_hi (a));
  a += 2;
  put_reg (sp, a);

  /** 1011 1000 010w 0011		RMPA.size */

  {
  int count = get_reg (r3);
  int list1 = get_reg (a0);
  int list2 = get_reg (a1);
  long long sum = get_reg_ll (r3r1r2r0) & 0xffffff;

  while (count)
    {
      if (w)
	{
	  a = sign_ext (mem_get_hi (list1), 16);
	  b = sign_ext (mem_get_hi (list2), 16);
	}
      else
	{
	  a = sign_ext (mem_get_qi (list1), 8);
	  b = sign_ext (mem_get_qi (list2), 8);
	}
      tprintf("%lld + %d * %d = ", sum, a, b);
      sum += a * b;
      tprintf("%lld\n", sum);
      list1 += w ? 2 : 1;
      list2 += w ? 2 : 1;
      count --;
    }
  put_reg (r3, count);
  put_reg (a0, list1);
  put_reg (a1, list2);
  put_reg (r2r0, (int)(sum & 0xffffffffU));
  put_reg (r1, (int)(sum >> 32));
  }

  /** 1011 ddd w dd10 1110		ROLC.size dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  rot_op (dc, 1, 1);

  /** 1010 ddd w dd10 1110		RORC.size dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  rot_op (dc, 1, -1);

  /** 1110 ddd w dd10 immm		ROT.size #IMM, dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  rot_op (dc, IMM4(), -1);

  /** 1010 ddd w dd11 1111		ROT.size R1H,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  a = sign_ext (get_reg (r1h), 8);
  rot_op (dc, a, -1);

  /** 1101 1111				RTS */

  put_reg (pc, mem_get_si (get_reg (sp)));
  put_reg (sp, get_reg (sp) + 4);

  /** 0000 0001 1001 ddd w dd10 1110	SBB.size #IMM, dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  imm = IMM (w+1);
  MATH_OP (dc, imm, !carry, -);

  /** 0000 0001 1sss ddd w dd ss 0110	SBB.size src,dest */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, w+1);
  dc = decode_dest23 (ddd, dd, w+1);
  MATH_OP (dc, get_src (sc), !carry, -);

  /** 1101 ddd1 dd11 cond		SCcond dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, 2);
  if (condition_true (cond))
    put_dest (dc, 1);
  else
    put_dest (dc, 0);

  /** 1011 1000 110w 0011		SCMPU.size */

  ta0 = get_reg (a0);
  ta1 = get_reg (a1);

  for (;;)
    {
      t0 = mem_get_qi (ta0);
      t2 = mem_get_qi (ta1);
      if (w)
	{
	  t1 = mem_get_qi (ta0 + 1);
	  t3 = mem_get_qi (ta1 + 1);
	}
      dif = t0 - t2;
      if (dif == 0 && t0 != 0 && w)
	dif = t1 - t3;
      set_oszc (dif, 1, dif > 0);

      ta0 += w ? 2 : 1;
      ta1 += w ? 2 : 1;

      if (t0 == 0 || t0 != t2)
	break;
      if (w && (t1 == 0 || t1 != t3))
	break;
    }

  /** 1111 ddd w dd00 immm		SHA.size #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  shift_op (dc, 1, IMM4(), 1);

  /** 1010 ddd0 dd10 0001		SHA.L #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, 4);
  imm = sign_ext (IMM(1), 8);
  shift_op (dc, 1, imm, 1);

  /** 1011 ddd w dd11 1110		SHA.size R1H,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  a = sign_ext (get_reg (r1h), 8);
  shift_op (dc, 1, a, 1);

  /** 1100 ddd0 dd01 0001		SHA.L	R1H,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, 4);
  a = sign_ext (get_reg (r1h), 8);
  shift_op (dc, 1, a, 1);

  /** 1100 ddd0 dd10 0001		SHANC.L #IMM,dest */

  M32C_ONLY();
  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, 4);
  imm = sign_ext (IMM(1), 8);
  shift_op (dc, 1, imm, 0);

  /** 1110 ddd w dd00 immm		SHL.size #IMM, dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  shift_op (dc, 0, IMM4(), 1);

  /** 1001 ddd0 dd10 0001		SHL.L #IMM, dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, 4);
  imm = sign_ext (IMM(1), 8);
  shift_op (dc, 0, imm, 1);

  /** 1010 ddd w dd11 1110		SHL.size R1H,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  a = sign_ext (get_reg (r1h), 8);
  shift_op (dc, 0, a, 1);

  /** 1100 ddd0 dd00 0001		SHL.L R1H,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, 4);
  a = sign_ext (get_reg (r1h), 8);
  shift_op (dc, 0, a, 1);

  /** 1000 ddd0 dd10 0001		SHLNC.L #IMM,dest */

  M32C_ONLY();
  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, 4);
  imm = sign_ext (IMM(1), 8);
  shift_op (dc, 0, imm, 0);

  /** 1011 0010 100w 0011		SIN.size */

  v = get_reg (a0);
  a = get_reg (a1);
  b = get_reg (r3);
  if (b) for (;b;)
    {
      if (w)
	mem_put_hi(a, mem_get_hi (v));
      else
	mem_put_qi(a, mem_get_qi (v));
      a += w ? 2 : 1;
      b --;
    }
  put_reg (a0, v);
  put_reg (a1, a);
  put_reg (r3, b);

  /** 1011 0110 100w 0011		SMOVB.size */

  v = get_reg (a0);
  a = get_reg (a1);
  b = get_reg (r3);
  if (b) for (;b;)
    {
      if (w)
	mem_put_hi(a, mem_get_hi (v));
      else
	mem_put_qi(a, mem_get_qi (v));
      v -= w ? 2 : 1;
      a -= w ? 2 : 1;
      b --;
    }
  put_reg (a0, v);
  put_reg (a1, a);
  put_reg (r3, b);

  /** 1011 0000 100w 0011		SMOVF.size */

  v = get_reg (a0);
  a = get_reg (a1);
  b = get_reg (r3);
  if (b) for (;b;)
    {
      if (w)
	mem_put_hi(a, mem_get_hi (v));
      else
	mem_put_qi(a, mem_get_qi (v));
      v += w ? 2 : 1;
      a += w ? 2 : 1;
      b --;
    }
  put_reg (a0, v);
  put_reg (a1, a);
  put_reg (r3, b);

  /** 1011 1000 100w 0011		SMOVU.size */

  v = get_reg (a0);
  a = get_reg (a1);
  do
    {
      if (w)
	mem_put_hi(a, (t0 = mem_get_hi (v)));
      else
	mem_put_qi(a, (t0 = mem_get_qi (v)));
      v += w ? 2 : 1;
      a += w ? 2 : 1;
      if (t0 == 0
	  || (w && ((t0 & 0xff) == 0 || (t0 & 0xff00) == 0)))
	break;
    } while (1);
  put_reg (a0, v);
  put_reg (a1, a);

  /** 1011 0100 100w 0011		SOUT.size */

  v = get_reg (a0);
  a = get_reg (a1);
  b = get_reg (r3);
  for (;b;)
    {
      if (w)
	mem_put_hi(a, mem_get_hi (v));
      else
	mem_put_qi(a, mem_get_qi (v));
      v += w ? 2 : 1;
      b --;
    }
  put_reg (a0, v);
  put_reg (a1, a);
  put_reg (r3, b);

  /** 1011 1000 000w 0011		SSTR.size */

  a = get_reg (a1);
  b = get_reg (r3);
  v = get_reg (w ? r0 : r0l);
  for (;b;)
    {
      if (w)
	mem_put_hi(a, v);
      else
	mem_put_qi(a, v);
      a += w ? 2 : 1;
      b --;
    }
  put_reg (a1, a);
  put_reg (r3, b);

  /** 0000 0001 1101 ddd1 dd01 0src	STC src,dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, 4);
  sc = decode_cr_b (src, CR_B_DMA0);
  a = get_src (sc);
  put_dest (dc, a);

  /** 0000 0001 1101 ddd1 dd01 1src	STC src,dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, 2);
  sc = decode_cr_b (src, CR_B_DCT0);
  a = get_src (sc);
  put_dest (dc, a);

  /** 1101 ddd1 dd01 0src		STC src,dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, 4);
  sc = decode_cr_b (src, CR_B_INTB);
  a = get_src (sc);
  put_dest (dc, a);

  /** 1011 0110 1101 0011		STCX abs16,abs24 */

  NOTYET();

  /** 1001 ddd w dd01 1111		STNZ.size #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  imm = IMM(w+1);
  if (! FLAG_Z)
    put_dest (dc, imm);

  /** 1001 ddd w dd00 1111		STZ.size #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  imm = IMM(w+1);
  if (FLAG_Z)
    put_dest (dc, imm);

  /** 1001 ddd w dd11 1111		STZX.size #IMM1,#IMM2,dest */

  prefix (0, 1, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  a = IMM(w+1);
  b = IMM(w+1);
  if (FLAG_Z)
    put_dest (dc, a);
  else
    put_dest (dc, b);

  /** 1000 ddd w dd11 1110		SUB.size:G #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23(ddd, dd, w+1);
  imm = IMM(w+1);
  MATH_OP (dc, imm, 0, -);

  /** 1001 ddd0 dd11 0001		SUB.L:G #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23(ddd, dd, 4);
  imm = IMM(4);
  MATH_OP (dc, imm, 0, -);

  /** 00dd 111w				SUB.size:S #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest2(dd, w+1);
  imm = IMM (w+1);
  MATH_OP (dc, imm, 0, -);

  /** 1sss ddd w dd ss 1010		SUB.size:G src,dest */

  prefix (1, 1, 0);
  sc = decode_src23(sss, ss, w+1);
  dc = decode_dest23(ddd, dd, w+1);
  b = get_src (sc);
  MATH_OP (dc, b, 0, -);

  /** 1sss ddd1 dd ss 0000		SUB.L:G src,dest */

  prefix (1, 1, 0);
  sc = decode_src23(sss, ss, 4);
  dc = decode_dest23(ddd, dd, 4);
  b = get_src (sc);
  MATH_OP (dc, b, 0, -);

  /** 1001 ddd0 dd01 0001		SUBX #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23(ddd, dd, 4);
  imm = sign_ext (IMM(1), 8);
  MATH_OP (dc, imm, 0, -);

  /** 1sss ddd0 dd ss 0000		SUBX src,dest */

  prefix (1, 1, 0);
  sc = decode_src23(sss, ss, 1);
  dc = decode_dest23(ddd, dd, 4);
  b = sign_ext (get_src (sc), 8);
  MATH_OP (dc, b, 0, -);

  /** 1001 ddd w dd11 1110		TST.size:G #IMM,dest */

  prefix (0, 0, 0);
  dc = decode_dest23 (ddd, dd, w+1);
  imm = IMM(w+1);
  a = get_src (dc);
  v = a & imm;
  set_sz (v, w+1);

  /** 00dd 110w				TST.size:S #IMM,dest */

  prefix (0, 0, 0);
  dc = decode_dest2 (dd, w+1);
  imm = IMM(w+1);
  a = get_src (dc);
  v = a & imm;
  set_sz (v, w+1);

  /** 0000 0001 1sss ddd w dd ss 1001	TST.size:G src,dest */

  prefix (0, 0, 0);
  sc = decode_src23 (sss, ss, w+1);
  dc = decode_dest23 (ddd, dd, w+1);
  b = get_src (sc);
  a = get_src (dc);
  v = a & b;
  set_sz (v, w+1);

  /** 1111 1111				UND */

  trigger_fixed_interrupt (0xffffdc);

  /** 1011 0010 0000 0011		WAIT */

  ;

  /** 1101 ddd w dd00 1src		XCHG.size src,dest */

  dc = decode_dest23 (ddd, dd, w+1);
  sc = decode_src3 (src, w+1);
  a = get_src (dc);
  b = get_src (sc);
  put_dest (dc, b);
  put_dest (sc, a);

  /** 1001 ddd w dd00 1110		XOR.size #IMM,dest */

  prefix (0, 1, 0);
  dc = decode_dest23(ddd, dd, w+1);
  imm = IMM(w+1);
  LOGIC_OP (dc, imm, ^);

  /** 1sss ddd w dd ss 1001		XOR.size src,dest */

  prefix (1, 1, 0);
  sc = decode_src23(sss, ss, w+1);
  dc = decode_dest23(ddd, dd, w+1);
  b = get_src (sc);
  LOGIC_OP (dc, b, ^);

/** */

  return step_result;
}
